package query

import (
	. "common/tools"
	"errors"
	. "github.com/xormplus/builder"
	"reflect"
	"strings"
)

type Filter struct {
	Operator string      `json:"operator"`
	Value    interface{} `json:"value"`
	Property string      `json:"property"`
	Group    string      `json:"group"`
	IsDate   bool        `json:"isDate"`
}

func (f *Filter) CaseProperty() string {
	return Camel2Case(f.Property)
}

type Filters []Filter

func EQ(f *Filter) (*Cond, error) {
	var r Cond = Eq{f.CaseProperty(): f.Value}
	return &r, nil
}

func NEQ(f *Filter) (*Cond, error) {
	var r Cond = Neq{f.CaseProperty(): f.Value}
	return &r, nil
}

func GTEQ(f *Filter) (*Cond, error) {
	var r = Expr(f.CaseProperty()+">=?", f.Value)
	return &r, nil
}

func LTEQ(f *Filter) (*Cond, error) {
	var r = Expr(f.CaseProperty()+"<=?", f.Value)
	return &r, nil
}

func LIKE(f *Filter) (*Cond, error) {
	v, _ := f.Value.(string)
	var r Cond = Like{f.CaseProperty(), v}
	return &r, nil
}

func NOTLIKE(f *Filter) (*Cond, error) {
	v, _ := f.Value.(string)
	var r = Expr(f.CaseProperty()+" not like ?", "%"+v+"%")
	return &r, nil
}

func BETWEEN(f *Filter) (*Cond, error) {
	var vt []interface{}
	switch reflect.TypeOf(f.Value).Kind() {
	case reflect.Slice, reflect.Array:
		s := reflect.ValueOf(f.Value)
		for i := 0; i < s.Len(); i++ {
			vt = append(vt, s.Index(i).Interface())
		}
	}
	if len(vt) == 0 || len(vt) == 1 {
		var r = NewCond()
		return &r, errors.New("BETWEEN的值应该是包含2个数据项的数组")
	}
	var r Cond = Between{Col: f.CaseProperty(), LessVal: vt[0], MoreVal: vt[1]}
	return &r, nil
}

func IN(f *Filter) (*Cond, error) {
	v, _ := f.Value.([]interface{})
	var r = In(f.CaseProperty(), v...)
	return &r, nil
}

func NOTIN(f *Filter) (*Cond, error) {
	v, _ := f.Value.([]interface{})
	var r = NotIn(f.Property, v...)
	return &r, nil
}
func ISNULL(f *Filter) (*Cond, error) {
	var r Cond = IsNull{f.Property}
	return &r, nil
}
func NOTNULL(f *Filter) (*Cond, error) {
	var r = Expr(f.Property + " not null")
	return &r, nil
}
func INSTART(f *Filter) (*Cond, error) {
	v, _ := f.Value.(string)
	var r = Expr(f.Property+" like ?", v+"%")
	return &r, nil
}

func NOTINSTART(f *Filter) (*Cond, error) {
	v, _ := f.Value.(string)
	var r = Expr(f.Property+" not like ?", v+"%")
	return &r, nil
}

func FilterToCond(f *Filter) (*Cond, error) {
	var r *Cond
	switch strings.ToUpper(f.Operator) {
	case "EQ":
		return EQ(f)
	case "NEQ":
		return NEQ(f)
	case "GTEQ":
		return GTEQ(f)
	case "LTEQ":
		return LTEQ(f)
	case "LIKE":
		return LIKE(f)
	case "NOTLIKE":
		return NOTLIKE(f)
	case "BETWEEN":
		return BETWEEN(f)
	case "IN":
		return IN(f)
	case "NOTIN":
		return NOTIN(f)
	case "ISNULL":
		return ISNULL(f)
	case "NOTNULL":
		return NOTNULL(f)
	case "INSTART":
		return INSTART(f)
	case "NOTINSTART":
		return NOTINSTART(f)
	}
	return r, errors.New("不支持该运算符：" + f.Operator)
}

func FiltersToConds(fs *Filters) (*[]Cond, error) {
	var result []Cond
	var err error
	for i := 0; i < len(*fs); i++ {
		f := (*fs)[i]
		v, err1 := FilterToCond(&f)
		if err1 != nil {
			err = err1
			break
		}
		result = append(result, *v)
	}
	return &result, err
}

func CondsToWriter(conds *[]Cond) (*BytesWriter, error) {
	w := NewWriter()
	var c Cond
	for i, cond := range *conds {
		if i == 0 {
			c = And(cond)
		} else {
			c = c.And(cond)
		}
	}
	err := c.WriteTo(w)
	return w, err
}

func FiltersToWriter(fs *Filters) (*BytesWriter, error) {
	conds, err := FiltersToConds(fs)
	if err != nil {
		return nil, err
	}
	writer, err := CondsToWriter(conds)
	return writer, err
}
